/*
 * Group.java
 *
 * Created on 20 marzo 2004, 10.28
 */

package net.ermannofranco.xml.schema;

import net.ermannofranco.xml.Static;
import net.ermannofranco.xml.SyntaxException;

/**
 * 
 * @author ermanno (ermanno.franco@gmail.com)
 */
public class Group extends SchemaTag {
	// non implementa ITagCollection perche' non aggiungo elem

	private static final long serialVersionUID = -4197628065322688951L;
	private static final int ALL = 2;
	private static final int CHOICE = 3;
	private static final int SEQUENCE = 4;
	private int gestoreContenuto = 0;

	// private boolean refAssigned;
	private boolean named;

	// public static int UNBOUNDED = 0;

	/**
	 * Creates a new instance of Group Protetto
	 * 
	 * @param level
	 *            livello di indentazione
	 * @param container
	 *            tag contenitore
	 */
	protected Group(int level, ISchemaTag container) {
		super("group", level, container);
	}

	/**
	 * @return
	 */
	public Sequence setSequence() {
		if (gestoreContenuto > 0)
			throw new SchemaException("Contenuto di Group gia' assegnato");
		Sequence s = new Sequence(getLevel() + 1, this, false);
		add(s);
		gestoreContenuto = SEQUENCE;
		return s;
	}

	/**
	 * @return
	 */
	public Choice setChoice() {
		if (gestoreContenuto > 0)
			throw new SchemaException("Contenuto di Group gia' assegnato");
		Choice s = new Choice(getLevel() + 1, this);
		add(s);
		gestoreContenuto = CHOICE;
		return s;
	}

	/**
	 * @return
	 */
	public All setAll() {
		if (gestoreContenuto > 0)
			throw new SchemaException("Contenuto di Group gia' assegnato");
		All s = new All(getLevel() + 1, this);
		add(s);
		gestoreContenuto = ALL;
		return s;
	}

	/**
	 * @param ref
	 * @return
	 */
	public Group setRef(Group ref) {
		if (named)
			throw new SchemaException("nome o ref gia' assegnato, "
					+ getClass().getName() + ":(" + getName() + ")");

		addAttr("ref", feedFormPrefix(ref.getGroupName()));
		// refAssigned=true;
		named = true;
		return this;
	}

	private String getGroupName() {
		return getAttribute("name");
	}

	/**
	 * @param name
	 * @return
	 */
	public Group setName(String name) {
		if (named)
			throw new SchemaException("nome o ref gia' assegnato, "
					+ getClass().getName() + ":(" + getName() + ")");
		Static.validateNMToken(name);

		addAttr("name", name);
		named = true;
		return this;
	}

	/**
	 * @param minOccurs
	 * @return
	 */
	public Group setMinOccurs(int minOccurs) {
		if (minOccurs < 0)
			throw new SyntaxException(minOccurs + " non valido in minOccurs: "
					+ getName());
		if (getLevel() == 1)
			throw new SchemaException("minOccurs non valido al primo livello: "
					+ getName());// al 1 livello non e' ammesso
		addAttr("minOccurs", "" + minOccurs);
		return this;
	}

	/**
	 * @param maxOccurs
	 * @return
	 */
	public Group setMaxOccurs(int maxOccurs) {
		if (maxOccurs < 0)
			throw new SyntaxException(maxOccurs + " non valido in maxOccurs: "
					+ getName());
		if (getLevel() == 1)
			throw new SchemaException("maxOccurs non valido al primo livello: "
					+ getName());// al 1 livello non e' ammesso
		if (maxOccurs == Integer.MAX_VALUE) {
			addAttr("maxOccurs", "unbounded");
		} else {
			addAttr("maxOccurs", "" + maxOccurs);
		}
		return this;
	}

	/**
	 * Allow zero or unbounded occurs. Shortcut for
	 * setMinOccurs(0).setUnboundedMaxOccurs().
	 * 
	 * @return this.
	 */
	public Group setAllPossibleOccurs() {
		return setMinOccurs(0).setUnboundedMaxOccurs();
	}

	/**
	 * Shortcut for setMinOccurs(0).setMaxOccurs(1). Remember: if maxOccurs is
	 * not specified in element, default is 1 anyway.
	 * 
	 * @return this.
	 */
	public Group setZeroOrOneOccurs() {
		return setMinOccurs(0).setMaxOccurs(1);
	}

	/**
	 * Shortcut for setMinOccurs(0).
	 * 
	 * @return this.
	 */
	public Group setZeroMinOccurs() {
		return setMinOccurs(0);
	}

	/**
	 * add maxOccurs="unbounded"
	 * 
	 * @return
	 */
	public Group setUnboundedMaxOccurs() {
		return setMaxOccurs(Integer.MAX_VALUE);
	}

	/**
	 * aggiunge un tag Annotation che contiene un tag Documentation
	 * 
	 * @param explanation
	 *            Stringa di documentazione
	 * @return autoriferimento all'oggetto corrente
	 */
	public Group addDocumentation(String explanation) {
		addAnnotation().addDocumentation(explanation);
		return this;
	}

	/**
	 * aggiunge un tag Annotation che contiene un tag Documentation
	 * 
	 * @param explanation
	 *            testo della documentazione
	 * @param language
	 *            attributo di xml:lang, seguire le regole di i18n
	 * @return riferimento all'oggetto corrente
	 */
	public Group addDocumentation(String explanation, String language) {
		addAnnotation().addDocumentation(explanation, language);
		return this;
	}
}
